package it.test.dao;

import it.test.commons.BasePojo;
import it.test.commons.DTO;
import it.test.commons.DTOImpl;

import java.io.Serializable;
import java.lang.reflect.ParameterizedType;
import java.sql.SQLException;
import java.util.Iterator;
import java.util.List;

import org.hibernate.Criteria;
import org.hibernate.HibernateException;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.criterion.Projections;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.slf4j.Marker;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.DataAccessException;
import org.springframework.orm.hibernate3.HibernateCallback;
import org.springframework.orm.hibernate3.HibernateTemplate;

public class AbstractBaseDAO<T extends BasePojo, ID extends Serializable> implements BaseDAO<T, ID> {
	
	
	protected Logger log = LoggerFactory.getLogger(this.getClass());
	private Class<T> persistentClass;
	
	@SuppressWarnings("unchecked")
	public AbstractBaseDAO(){
		this.persistentClass = (Class<T>) ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[0];

	}
	
	public Class<T> getPersistentClass() {
		return persistentClass;
	}

	
	@Autowired
	protected SessionFactory sessionFactory;

	/**
	 * Ricerca oggetto tramite id univoco
	 * @author marco
	 * 
	 */
	@SuppressWarnings("unchecked")
	@Override
	public DTO<T> find(ID id)  throws DataAccessException{
		log.debug("DAO find(ID id)");
		return new DTOImpl<T>((T)this.sessionFactory.getCurrentSession().get(persistentClass, id));
//		return new DTOImpl<T>(this.hibernateTemplate.get(persistentClass, id));
		
	}

	@Override
	public void save(DTO<T> dto) throws DataAccessException {
		log.debug("DAO save(DTO<T> dto)");
		log.debug("Saving instance of " + this.persistentClass);
		this.sessionFactory.getCurrentSession().save(dto.getBasePojo());
//		this.hibernateTemplate.save(dto.getBasePojo());
		log.debug("Save succesfull");
	}

	@Override
	public void saveOrUpdate(DTO<T> dto) throws DataAccessException {
		log.debug("DAO saveOrUpdate(DTO<T> dto)");
		log.debug("Saving/Update instance of " + this.persistentClass);
		this.sessionFactory.getCurrentSession().saveOrUpdate(dto.getBasePojo());
//		this.hibernateTemplate.saveOrUpdate(dto.getBasePojo());
		log.debug("SaveOrUpdate succesfull");
	}

	@Override
	public void update(DTO<T> dto) throws DataAccessException {
		this.sessionFactory.getCurrentSession().update(dto.getBasePojo());
//		this.hibernateTemplate.update(dto.getBasePojo());
	}

	@Override
	public void delete(DTO<T> dto) throws DataAccessException {
		this.sessionFactory.getCurrentSession().delete(dto.getBasePojo());
//		this.hibernateTemplate.delete(dto.getBasePojo());	
	}

	@SuppressWarnings("unchecked")
	@Override
	public List<T> findAll() throws DataAccessException {
		return (List<T>)this.sessionFactory.getCurrentSession().createCriteria(persistentClass).list();
//		return this.hibernateTemplate.execute(new HibernateCallback<List<T>>() {
//			@SuppressWarnings("unchecked")
//			public List<T> doInHibernate(Session session) throws HibernateException,
//					SQLException {
//				return session.createCriteria(persistentClass).list();
//				
//			}
//		});

	}

	@SuppressWarnings("unchecked")
	@Override
	public List<T> findInRange(final int firstResult,final int maxResults) throws DataAccessException {
		Session s = this.sessionFactory.getCurrentSession();
		Criteria c = s.createCriteria(persistentClass);
		c.setFirstResult(firstResult);
		c.setMaxResults(maxResults);
		return (List<T>)c.list();
		
//		return this.hibernateTemplate.execute(new HibernateCallback<List<T>>() {
//			@SuppressWarnings("unchecked")
//			public List<T> doInHibernate(Session session) throws HibernateException,
//					SQLException {
//				Criteria c = session.createCriteria(persistentClass);
//				c.setFirstResult(firstResult);
//				c.setMaxResults(maxResults);
//				return c.list();
//			}
//		});

	}

	@Override
	public long count() throws DataAccessException {
		Session s = this.sessionFactory.getCurrentSession();
		Criteria c = s.createCriteria(persistentClass);
		c.setProjection(Projections.rowCount());
		return new Long(c.list().size());
		
//		return this.hibernateTemplate.execute(new HibernateCallback<Long>() {
//			public Long doInHibernate(Session session) throws HibernateException,
//					SQLException {
//				Criteria c = session.createCriteria(persistentClass);
//				c.setProjection(Projections.rowCount());
//				return new Long(c.list().size());
//				
//			}
//		});

	}

	
	
}
